﻿using ArtMath.Attribute;
using ArtMath.Component.Point;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.PointCollection;
using System;
using System.Collections.Generic;
using System.Linq;

namespace ArtMath.Component.Manager
{
    /// <summary>
    /// 交点管理器基类
    /// </summary>
    [Serializable]
    public abstract class CrossoverPointsManagerBase : ComponentManagerBase
    {
        List<CrossoverPointBase> points = new List<CrossoverPointBase>();
        LineBase line1, line2;
        public CrossoverPointsManagerBase(SketchPad pad, string name, LineBase line1, LineBase line2, bool addToList = true) : base(pad, name, ToolTypeName.jdglq, addToList)
        {
            Line1 = line1;
            Line2 = line2;
        }
        public override PointD MassPoint
        {
            get
            {
                return Utility.GetBaryCenter(Points.Select((CrossoverPointBase pt) => { return pt.MassPoint; }).ToList());
            }
        }
        public override PointCollectionsManager Skeleton
        {
            get
            {
                PointCollectionsManager res = new PointCollectionsManager();
                foreach (CrossoverPointBase item in Points)
                {
                    res.AddPointCollection(item.Skeleton);
                }
                return res;
            }
        }
        public override PointCollectionsManager PSkeleton
        {
            get
            {
                PointCollectionsManager res = new PointCollectionsManager();
                foreach (CrossoverPointBase item in Points)
                {
                    res.AddPointCollection(item.PSkeleton);
                }
                return res;
            }
        }
        public override PointCollectionsManager NewSkeleton
        {
            get
            {
                PointCollectionsManager res = new PointCollectionsManager();
                foreach (CrossoverPointBase item in Points)
                {
                    res.AddPointCollection(item.NewSkeleton);
                }
                return res;
            }
        }
        public override PointCollectionsManager NewPSkeleton
        {
            get
            {
                PointCollectionsManager res = new PointCollectionsManager();
                foreach (CrossoverPointBase item in Points)
                {
                    res.AddPointCollection(item.NewPSkeleton);
                }
                return res;
            }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}1", "Line")]
        public LineBase Line1
        {
            get { return line1; }
            set
            {
                line1?.ComponentManagers.Remove(this);
                line1 = value;
                line1?.ComponentManagers.Insert(0, this);
            }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}2", "Line")]
        public LineBase Line2
        {
            get { return line2; }
            set
            {
                line2?.ComponentManagers.Remove(this);
                line2 = value;
                line2?.ComponentManagers.Insert(0, this);
            }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("CrossoverPoint")]
        public List<CrossoverPointBase> Points
        {
            get { return points; }
        }
        public override PointD AnchorPoint(PropertyDisplayer disp)
        {
            double xSum = 0, ySum = 0;
            foreach (CrossoverPointBase item in Points)
            {
                xSum += item.Pxy.X;
                ySum += item.Pxy.Y;
            }
            return new PointD(xSum / Points.Count, ySum / Points.Count);
        }
        public override void InChildrenIterator(Predicate<ShapeBase> act)
        {
            if (act == null) return;
            foreach (CrossoverPointBase item in Points)
            {
                if (item == null) continue;
                if (!act(item)) break;
            }
        }
        public override void ForEachPoint(Predicate<PointBase> act)
        {
            if (act == null) return;
            foreach (CrossoverPointBase item in Points)
            {
                if (!act(item))
                {
                    break;
                }
            }
        }
        protected override void ForEachManagedComponent(Predicate<Base> act)
        {
            if (act == null) return;
            if (!act(Line1)) return;
            if (!act(Line2)) return;
        }
        protected Dictionary<CrossoverPointBase, PointD> GetDistribution(out CrossoverPointBase[] redundantPoints,
            out PointD[] redundantNewCoordinates)
        {
            PointCollectionsManager mgr = Line1.NewSkeleton.Intersect(Line2.NewSkeleton);
            if (mgr == null)
            {
                redundantPoints = Points.ToArray();
                redundantNewCoordinates = null;
                return null;
            }
            else
            {
                Dictionary<CrossoverPointBase, PointD> dic = new Dictionary<CrossoverPointBase, PointD>();
                bool[] flag;
                int index = 0;
                List<PointD> cross = new List<PointD>();
                foreach (PointCollectionBase item in mgr.PointCollections)
                {
                    DiscontinuityPoint dp = item as DiscontinuityPoint;
                    if (dp != null)
                    {
                        foreach (PointD pt in dp.Points)
                        {
                            cross.Add(Pad.XYToPxy(pt));
                        }
                    }
                }
                if (cross.Count < Points.Count)
                {
                    redundantPoints = new CrossoverPointBase[Points.Count - cross.Count];
                    redundantNewCoordinates = null;
                    flag = new bool[Points.Count];
                    for (int i = 0; i < cross.Count; i++)
                    {
                        double minDist = double.PositiveInfinity;
                        int minIndex = -1;
                        for (int j = 0; j < flag.Length; j++)
                        {
                            if (!flag[j])
                            {
                                double dist = cross[i].DistanceTo(Points[j].Pxy);
                                if (dist < minDist)
                                {
                                    minDist = dist;
                                    minIndex = j;
                                }
                            }
                        }
                        flag[minIndex] = true;
                        dic.Add(Points[minIndex], cross[i]);
                    }
                    for (int i = 0; i < flag.Length; i++)
                    {
                        if (!flag[i])
                        {
                            redundantPoints[index++] = Points[i];
                        }
                    }
                }
                else
                {
                    redundantPoints = null;
                    redundantNewCoordinates = cross.Count == Points.Count ? null : new PointD[cross.Count - Points.Count];
                    flag = new bool[cross.Count];
                    for (int i = 0; i < Points.Count; i++)
                    {
                        double minDist = double.PositiveInfinity;
                        int minIndex = -1;
                        for (int j = 0; j < flag.Length; j++)
                        {
                            if (!flag[j])
                            {
                                double dist = cross[j].DistanceTo(Points[i].Pxy);
                                if (dist < minDist)
                                {
                                    minDist = dist;
                                    minIndex = j;
                                }
                            }
                        }
                        flag[minIndex] = true;
                        dic.Add(Points[i], cross[minIndex]);
                    }
                    for (int i = 0; i < flag.Length; i++)
                    {
                        if (!flag[i])
                        {
                            redundantNewCoordinates[index++] = cross[i];
                        }
                    }
                }
                return dic.Count == 0 ? null : dic;
            }
        }
    }
}
